package com.gitee.cashzhang27.test.boot.other.controller;

import com.gitee.cashzhang27.test.boot.other.entity.User;
import com.gitee.cashzhang27.test.boot.other.service.UserService;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/*
@CacheConfig 可以抽取缓存公共配置
 */

/**
 * @author Cash Zhang
 * @version v1.0
 * @since 2019/02/16 21:48
 */
@RestController
@RequestMapping("user")
@AllArgsConstructor
public class UserController {

  private UserService userService;

  private RedisTemplate redisTemplate;

  @GetMapping("/testUserRedisTemplate")
  public void testUserRedisTemplate() {
    User zhangsan = User.builder().id(1).username("zhangsan").password("123456").build();
    List<User> user = new ArrayList<>();
    user.add(zhangsan);
    redisTemplate.opsForList().leftPush("user:" + zhangsan.getId() + ":", user);
  }

  @CachePut(cacheNames = "user", key = "#result.id", condition = "#result != null ")
  @GetMapping("/add/{i}")
  public User add(@PathVariable("i") String i) {
    User zhangsan = User.builder().password("123456").build();
    zhangsan.setUsername("zhangsan" + i);
    boolean flag = userService.save(zhangsan);
    if (flag) {
      return zhangsan;
    } else {
      return null;
    }
  }

  /*
  @CacheEvict 清除缓存
   */

  /**
   * <p>allEntries 删除所有缓存
   * <p>beforeInvocation： 是否在方法之前执行
   */
  @CacheEvict(cacheNames = "user", key = "#id")
  @GetMapping("detelte/{id}")
  public void delete(@PathVariable("id") String id) {
    userService.removeById(id);
  }

/*
     @CachePut：既调用方法，又更新缓存数据；
     修改了数据库的某个数据，同时更新缓存
     运行实际：
      1）、先调用目标方法
      2）、将目标方法结果范存起来
*/

  @CachePut(cacheNames = "user", key = "#result.id", condition = "#result != null ")
  @GetMapping("update/{id}")
  public User update(@PathVariable("id") Integer id) {
    User lisi = User.builder().id(id).username("lisi" + id).password("123456").build();
    boolean flag = userService.updateById(lisi);
    if (flag) {
      return lisi;
    } else {
      return null;
    }
  }


/*
   @Cacheable:将方法的运行结果进行缓存；以后再要相同的数据，直接从缓存中取，不用调用方法；
   CacheManager管理多个Cache组件的，对缓存的真正CRUD操作在Cache组件中，每一个缓存组件都有自己唯一一个名字；
   cacheManager：指定缓存管理器；或者cacheResolver指定获取解析器

   运行过程：
   @Cacheable： 1、方法运行之前，先查询Cache（缓存组件），按照cacheNames指定的名字获取； （CacheManager现货区响应的缓存），第一次获取缓存如果没有Cache组件会自动创建
   2、去Cache中查找缓存的内容，使用一个key，默认就是方法的参数； key是按照某种策略生成；默认是使用keyGenerator生成
   3、没有查到缓存就调用目标方法
   4、将目标方法返回的结果放进缓存中

   Cacheable标注的方法执行之前先来检查缓存中有没有这个数据，默认按照参数的值作为key查询缓存， 如果没有就运行方法并将结果放进缓存中，以后在调用就可以直接使用缓存中的数据

   核心： 1）、使用CacheManager按照名字得到Cache组件 2）、key使用keyGenerator生成的
*/

  /**
   * <p>cacheNames/value：指定缓存组件的名字；
   * key：缓存数据使用的key；可以用它来指定，默认是使用方法参数的值 1-方法返回值；
   * <p>注，key不能用#result 因为运行时机不对
   * <p>编写SpEL； #id；参数id的值 #a0 #p0 #root.args[0]
   */
  @Cacheable(cacheNames = "user", key = "#id")
  @GetMapping("get/{id}")
  public User getKey(@PathVariable("id") Integer id) {
    return userService.getById(id);
  }

  /**
   * <p>keyGenerator：key的生成器；可以自己指定key的生成器的组件id key/keyGenerator：二选一使用
   */
  @Cacheable(cacheNames = "user", keyGenerator = "myKeyGenerator")
  @GetMapping("getKeyGenerator/{id}")
  public User getKeyGenerator(@PathVariable("id") Integer id) {
    return userService.getById(id);
  }

  /**
   * <p> condition：指定符合条件的情况下才缓存
   * (第一个参数大于1才缓存)
   */
  @Cacheable(cacheNames = "user", condition = "#a0>1")
  @GetMapping("getKeyCondition/{id}")
  public User getKeyCondition(@PathVariable("id") Integer id) {
    return userService.getById(id);
  }

  /**
   * <p> unless：否定缓存；当unless指定条件为true，方法的返回值就不会被缓存
   * 可以获取到结果进行判断 unless = "#result == null"
   * <p>(第一个参数大于1就不缓存)
   */
  @Cacheable(cacheNames = "user", unless = "#a0>1")
  @GetMapping("getKeyUnless/{id}")
  public User getKeyUnless(@PathVariable("id") Integer id) {
    return userService.getById(id);
  }

  /**
   * sync：是否使用异步模式（异步模式 不支持unless）
   */
  @Cacheable(cacheNames = "user", sync = true)
  @GetMapping("getKeySync/{id}")
  public User getKeySync(@PathVariable("id") Integer id) {
    return userService.getById(id);
  }

  /*
  @Caching 里面可以配置复杂缓存规则
   */
}
